package com.ev.asl.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ev.asl.vo.*;
import com.ev.asl.vo.voBillOfPull.ShipmentsNoticeBodyVO;
import com.ev.asl.vo.voBillOfPull.ShipmentsNoticeHeadVO;
import com.ev.custom.service.MaterielService;
import com.ev.framework.config.ConstantForMES;
import com.ev.framework.utils.*;
import com.ev.asl.config.ApiParam;
import com.ev.asl.config.JiateConstant;
import com.ev.asl.config.KisApiUrlParam;
import com.ev.asl.dao.BillDao;
import com.ev.asl.service.KisBillOfPullService;
import com.ev.mes.dao.ProductionFeedingDao;
import com.ev.mes.dao.ProductionFeedingDetailDao;
import com.ev.mes.domain.*;
import com.ev.mes.service.ProductionPlanService;
import com.ev.mes.vo.ProductionFeedingBodyVO;
import com.ev.mes.vo.ProductionFeedingHeadVO;
import com.ev.scm.domain.DeliveryNoteDO;
import com.ev.scm.domain.DeliveryNoteItemDO;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class KisBillOfPullServiceImpl implements KisBillOfPullService {
    @Resource
    private BillDao billDao;
    @Resource
    private KisApiUrlParam kisApiUrlParam;
    @Resource
    private ProductionFeedingDetailDao productionFeedingDetailDao;
    @Resource
    private ProductionFeedingDao productionFeedingDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    ProductionPlanService productionPlanService;
    @Autowired
  private MaterielService materielService;

    /**限制频繁调用*/
    public Pair<Boolean,String> limitFrequentCalls(String redisKey){
        String key = ShiroUtils.getUserId() + redisKey;
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            return Pair.of(true,"禁止频繁操作同步！请 "+expire +"秒后重试");
        }
        //同一个登录人60秒内只可以操作一次
        redisTemplate.opsForValue().set(key, "Temporarily out of sync", 60l, TimeUnit.SECONDS);
        return Pair.of(false,"");
    }

    //时间转换  ---> String  Date
    public static Date timeToTranslateForDate(String strDate) {
        if(StringUtils.isNotBlank(strDate)){
            if(StringUtils.contains(strDate,"/")){
                strDate= strDate.replace("/", "-");
            }
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            ParsePosition pos = new ParsePosition(0);
            Date stToDate = formatter.parse(strDate, pos);
            return stToDate;
        }
        return null;
    }

    public Pair<Map<Long, Long>, Map<String, Long>> idsAndAuditTime(int sign) {
        Map<String, Object> map = Maps.newHashMapWithExpectedSize(1);
        Map<Long, Long> ids = new HashMap<>();
        Map<String, Long> itemIds = new HashMap<>();
        List<Map<String, Object>> allIds = new ArrayList<>();
        switch (sign) {
            case 72:
                //收料通知
                allIds = billDao.getReceiveNoticeIdsAndSign(map);
                break;
            case 83:
                //发货通知
                allIds = billDao.getShipmentsNoticeIdsAndSign(map);
                break;
            case 50:
                //BOM单
                allIds = billDao.getBomIdsAndSign(map);
                break;
            case 85:
                //生产计划  --->  对应金蝶的 生产任务单
                allIds = billDao.getProductionPlanAndTime(map);
                break;
            case 88:
                //生产投料单
                allIds = billDao.getProductionFeedingIdsAndSign(map);
                break;
            default:
                break;
        }
        if (!CollectionUtils.isEmpty(allIds)) {
            allIds.stream().forEach(aa -> {
                Long id = Long.parseLong(aa.get("id").toString());
                ids.put(id, id);
                itemIds.put(aa.getOrDefault("noticeIdEntryId",0).toString(), Long.parseLong(aa.getOrDefault("itemId",0).toString()));
            });
        }
        return Pair.of(ids, itemIds);
    }

    public Map<String, String> paramForApi(int itemClassId, Boolean sign,String param) {
        String week = DatesUtil.getBeginDayOfWeekOfString();
        //TODO 日期放开
//        String yesterday = "2021-12-10";   "  and t1.FCheckDate >= '2021-12-10' "
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId, sign);
        String dd = " and t1."+param+">=" + "'" + week + "'";
        paramForApi.put("Filter", dd);
        System.out.println("-----------------参数：" + paramForApi);
        return paramForApi;
    }

    public static void main(String[] args) {
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(83, false);
        String dd = " and t1."+"fcheckdate"+">=" + "'" + "2021-12-10" + "'";
        paramForApi.put("Filter", dd);
        System.out.println(JSON.toJSONString(paramForApi));
    }

    //标记定时任务执行
    public void markSynchronized(String keySign) {
        //记录同步次数  如果今天没有人同步，则定时任务触发执行同步 避免漏单
        //设置加班最迟22点，01点开始同步，十点之后的将不在同步
        redisTemplate.opsForValue().set(keySign, "sync+1", 3l, TimeUnit.HOURS);
    }

/**--------------------------------------------------------------------------------------------------------------------------*/

    /**
     * 发货通知
     */
    @Override
    public R shipmentsNoticeSync(int itemClassId) {
        //校验 + 限制频繁调用
        Pair<Boolean, String> pair = this.limitFrequentCalls("_shipmentsNotice");
        if (pair.getLeft()) {
            return R.error(pair.getRight());
        }
        //查询出通知所有的主键 和审核时间
        Pair<Map<Long, Long>, Map<String, Long>> allOldIds = idsAndAuditTime(itemClassId);
        Map<String, String> paramForApi = paramForApi3(itemClassId, false,"fcheckdate");
        R r = this.doPostOfApiForShipmentsNotice(kisApiUrlParam.getUrl_pull_bill(), paramForApi, allOldIds);
        //标记定时任务执行
        markSynchronized("shipmentsNotice_synchronized_002");
        return r;
    }
    public Map<String, String> paramForApi3(int itemClassId, Boolean sign,String param) {
        String week = DatesUtil.getBeginDayOfWeekOfString();
        //TODO 日期放开
//        String yesterday = "2021-12-10";    and t1.Fdate>='2021-12-10'  and isnull (t1.fcheckerid,0)>0
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId, sign);
        String dd = "  and isnull (t1.fcheckerid,0)>0 and t1.Fdate >=" + "'" + week + "'";
        paramForApi.put("Filter", dd);
        System.out.println("-----------------参数：" + paramForApi);
        return paramForApi;
    }

    public Map<String, String> paramForApi2(int itemClassId, Boolean sign,String param) {
        String yesterday = DatesUtil.getBeginDayOfYesterdayOfString();
        //TODO 日期放开
//        String yesterday = "2021-12-10"; fDate > '2022-12-12' and FStatus >0
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId, sign);
        String dd = " and t1.FStatus >0 and FDate >= " + "'" + yesterday + "'";
//        String dd = " and t1."+param+">=" + "'" + yesterday + "'";
        paramForApi.put("Filter", dd);
        System.out.println("-----------------参数：" + paramForApi);
        return paramForApi;
    }

    public R doPostOfApiForShipmentsNotice(String url, Map<String, String> params, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
        if (StringUtils.isNotBlank(result)) {
            Object parse = JSON.parse(result);
            ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
            System.out.println("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
            if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                // 0 为正常  1 异常
                return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
            }
            String datas = apiResultVOS.getDatas();
            List<HeadAndBodyVO> kisHeadAndBodyVO = JSON.parseArray(datas, HeadAndBodyVO.class);
            if (!CollectionUtils.isEmpty(kisHeadAndBodyVO)) {
                //保存 更新   interid_entryid
                keepUpdateForShipmentsNotice(kisHeadAndBodyVO, allOldIds);
            }
        }
        return R.ok();
    }

    public void keepUpdateForShipmentsNotice(List<HeadAndBodyVO> kisHeadAndBodyVO, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        List<ShipmentsNoticeHeadVO> headVOS = new ArrayList<>();
        List<ShipmentsNoticeBodyVO> bodyVOS = new ArrayList<>();
        for (HeadAndBodyVO vo : kisHeadAndBodyVO) {
            String billHead = vo.getBillHead();
            String billEntry = vo.getBillEntry();
            if (StringUtils.isNotBlank(billHead) && StringUtils.isNotBlank(billHead)) {
                ShipmentsNoticeHeadVO shipmentsNoticeHeadVO = JSON.parseObject(JSON.parse(billHead).toString(), ShipmentsNoticeHeadVO.class);
                List<ShipmentsNoticeBodyVO> shipmentsNoticeBodyVO = JSON.parseArray(billEntry, ShipmentsNoticeBodyVO.class);
                headVOS.add(shipmentsNoticeHeadVO);
                bodyVOS.addAll(shipmentsNoticeBodyVO);
            }
        }
        //更新 保存
        disposeHeadShipmentsNotice(headVOS, allOldIds.getLeft());
        disposeBodyShipmentsNotice(bodyVOS, allOldIds.getRight());
    }

    @Async("createPDFExecutor")
    public void disposeHeadShipmentsNotice(List<ShipmentsNoticeHeadVO> headVOS, Map<Long, Long> headIdsAndTime) {
        //字段匹配转换 更新 保存
        try {
            if (!CollectionUtils.isEmpty(headVOS)) {
                List<DeliveryNoteDO> saveVo = new ArrayList<>();
                List<DeliveryNoteDO> updateVo = new ArrayList<>();
                headVOS.stream().forEach(aa -> {
                    DeliveryNoteDO deliveryNoteDO = new DeliveryNoteDO();
                    if(ObjectUtils.isEmpty(aa.getFInterId())){
                        log.info(" ====================:aa.getFInterId(){}",aa.getFInterId());
                    }
                    long id = Long.parseLong(aa.getFInterId());
                    deliveryNoteDO.setId(id);
                    deliveryNoteDO.setDeliveryCode(aa.getFBillNo());
                    deliveryNoteDO.setClientId(ObjectUtils.isEmpty(aa.getFCustID()) ? null : Long.parseLong(aa.getFCustID()));
                    deliveryNoteDO.setSalesUser(ObjectUtils.isEmpty(aa.getFEmpID()) ? null : Long.parseLong(aa.getFEmpID()));
                    deliveryNoteDO.setDeptId(ObjectUtils.isEmpty(aa.getFDeptID()) ? null : Long.parseLong(aa.getFDeptID()));
                    deliveryNoteDO.setHarvestAddress(aa.getFFetchAdd());
                    deliveryNoteDO.setNoteTime(ObjectUtils.isEmpty(aa.getFCheckDate()) ? null : new Date(aa.getFCheckDate()));
                    deliveryNoteDO.setAuditor(ObjectUtils.isEmpty(aa.getFCheckerID()) ? null : Long.parseLong(aa.getFCheckerID()));
                    deliveryNoteDO.setAuditSign(179L);
                    deliveryNoteDO.setAuditTime(ObjectUtils.isEmpty(aa.getFCheckDate()) ? null : new Date(aa.getFCheckDate()));
                    deliveryNoteDO.setCreateBy(ObjectUtils.isEmpty(aa.getFBillerID()) ? null : Long.parseLong(aa.getFBillerID()));
                    deliveryNoteDO.setDelFlag(0);
                    if (headIdsAndTime.containsKey(id)) {
                        updateVo.add(deliveryNoteDO);
                    } else {
                        saveVo.add(deliveryNoteDO);
                    }
                });
                if (!CollectionUtils.isEmpty(saveVo)) {
                    billDao.batchSaveDeliveryNote(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    billDao.batchUpdateDeliveryNote(updateVo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 收料通知 头  异常！:{}",e);
        }
    }

    @Async("createPDFExecutor")
    public void disposeBodyShipmentsNotice(List<ShipmentsNoticeBodyVO> bodyVOS, Map<String, Long> bodyIdsAndHeadIds) {
        //字段匹配转换 更新 保存
        System.out.println("----------------body 原值：bodyIdsAndHeadIds：" + bodyIdsAndHeadIds);
        try {
            if (!CollectionUtils.isEmpty(bodyVOS)) {
                List<DeliveryNoteItemDO> saveVo = new ArrayList<>();
                List<DeliveryNoteItemDO> updateVo = new ArrayList<>();
                bodyVOS.stream().forEach(aa -> {
                    DeliveryNoteItemDO deliveryNoteItemDO = new DeliveryNoteItemDO();
                    deliveryNoteItemDO.setMainId(Long.parseLong(aa.getFInterId()));
                    deliveryNoteItemDO.setMaterielId(Long.parseLong(aa.getFItemID()));
                    deliveryNoteItemDO.setDeliveryCount(new BigDecimal(aa.getFauxqty()));
//                    new BigDecimal(aa.getFSecCoefficient());
                    //换算系数默认为1
                    deliveryNoteItemDO.setConvCoefficient(new BigDecimal("1"));
                    //主辅助单位输数量一致
                    deliveryNoteItemDO.setDeliveryCountSupport(new BigDecimal(aa.getFauxqty()));
                    deliveryNoteItemDO.setDeliveryCount(new BigDecimal(aa.getFauxqty()));
                    deliveryNoteItemDO.setSellUnitPrice(new BigDecimal(aa.getFauxprice()));
                    deliveryNoteItemDO.setSellAmount(new BigDecimal(aa.getFamount()));
                    deliveryNoteItemDO.setSupportUom(Long.parseLong(aa.getFUnitID()));
                    //取原单内码
                    deliveryNoteItemDO.setSourceId(Long.parseLong(aa.getFSourceInterId()));
                    deliveryNoteItemDO.setSourceType(Long.parseLong(aa.getFSourceTranType()));
                    //取 合同单号   如果不对 则可 添加订单单号  订单内码
                    deliveryNoteItemDO.setSourceCode(aa.getFSourceBillNo());
                    deliveryNoteItemDO.setDelFlag(0);

                    String noticeIdEntryId = aa.getFInterId() + "-" + aa.getFEntryID();

                    if (bodyIdsAndHeadIds.containsKey(noticeIdEntryId)) {
                        System.out.println("----------------body 更新：noticeIdEntryId" + noticeIdEntryId);
                        //采购入库可执行数量(辅单位) ---->设置为 已入库数量 更新时保留原值
                        deliveryNoteItemDO.setExecutableCount(null);
                        deliveryNoteItemDO.setId(bodyIdsAndHeadIds.get(noticeIdEntryId));
                        updateVo.add(deliveryNoteItemDO);
                    } else {
                        //作为更新或新增的标记
                        System.out.println("----------------body 新增：noticeIdEntryId" + noticeIdEntryId);
                        deliveryNoteItemDO.setNoticeidEntryid(noticeIdEntryId);
                        saveVo.add(deliveryNoteItemDO);
                    }
                });
                if (!CollectionUtils.isEmpty(saveVo)) {
                    billDao.batchSaveDeliveryNoteItem(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    billDao.batchUpdateDeliveryNoteItem(updateVo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 发货通知 明细  异常！");
        }
    }

/**--------------------------------------------------------------------------------------------------------------------------*/


    /**   生产计划  生产计划  --->  对应金蝶的 生产任务单   */
    @Override
    public R productionSync(int itemClassId) {
        //校验 + 限制频繁调用
        Pair<Boolean, String> pair = this.limitFrequentCalls("_production-plan");
        if (pair.getLeft()) {
            return R.error(pair.getRight());
        }
        //查询出通知所有的主键
        Pair<Map<Long, Long>, Map<String, Long>> allOldIds = idsAndAuditTime(itemClassId);
        Map<String, String> paramForApi = paramForApi(itemClassId, false,"FConfirmDate");
        R r = this.doPostOfApiForProductionPlan(kisApiUrlParam.getUrl_pull_bill(), paramForApi, allOldIds);
        //标记定时任务执行
        this.markSynchronized("production_plan_synchronized_004");
        return r;
    }

    public R doPostOfApiForProductionPlan(String url, Map<String, String> params, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
//        try{
            String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
            if (StringUtils.isNotBlank(result)) {
                Object parse = JSON.parse(result);
                ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
                System.out.println("------------生产计划：返回值 整理1  ----ApiResultVOS:" + apiResultVOS);
                if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                    // 0 为正常  1 异常
                    return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
                }
                String datas = apiResultVOS.getDatas();
                List<HeadAndBodyVO> kisHeadAndBodyVO = JSON.parseArray(datas, HeadAndBodyVO.class);
                if (!CollectionUtils.isEmpty(kisHeadAndBodyVO)) {
                    //保存 更新
                    //校验是否存在同等物料的工艺路线
                    Pair<Boolean, List<String>> booleanListPair = checkMaterielCraft(kisHeadAndBodyVO,allOldIds.getLeft());
                    if(!booleanListPair.getLeft()){
                        List<String> right = booleanListPair.getRight();
                        if(!CollectionUtils.isEmpty(right)){
                            StringBuilder sb = new StringBuilder("单据编号：");
                            for(String str:right){
                                sb.append(str);
                                sb.append(",");
                            }
                            sb.append("以上单据因无法匹配工艺路线，同步失败！");
                            return R.error(sb.toString());
                        }
                    }
                    return R.ok();
                }else{
                    return R.error("无单据可同步！");
                }
            }
            return R.error("无单据可同步！");
//        } catch (Exception e) {
//            log.info("生产计划--同步---调用api或转换异常：" + e.getMessage());
//            return R.error("调用api或转换异常：" + e.getMessage());
//        }
    }

    ////校验是否存在同等物料的工艺路线
    public Pair<Boolean,  List<String>> checkMaterielCraft(List<HeadAndBodyVO> kisHeadAndBodyVO, Map<Long, Long>allOldIds) {
        List<ProductionPlanVO> headVOS = new ArrayList<>();
        for (HeadAndBodyVO vo : kisHeadAndBodyVO) {
            String billHead = vo.getBillHead();
            if (StringUtils.isNotBlank(billHead)) {
                ProductionPlanVO productionPlanVO = JSON.parseObject(JSON.parse(billHead).toString(), ProductionPlanVO.class);
                headVOS.add(productionPlanVO);
            }
        }
//        List<String> haveNoCraftOfBillNo = new ArrayList<>();
        //能够匹配到工艺的生产计划
        if (!CollectionUtils.isEmpty(headVOS)) {
               disposeHeadProductionPlan(headVOS,allOldIds);
                return Pair.of(true, null);
            }
        return Pair.of(false, null);
    }

    public Map<Long, Integer> materielType(List<ProductionPlanVO> headVOS){
        List<Long> collect = headVOS.stream().map(e -> Long.parseLong(e.getFItemID())).collect(Collectors.toList());
       return materielService.getMaterielForSyc(collect);
    }

    @Async("createPDFExecutor")
    public void disposeHeadProductionPlan(List<ProductionPlanVO> headVOS, Map<Long, Long> bodyIdsAndHeadIds) {
        //字段匹配转换 更新 保存
//        try {
            if (!CollectionUtils.isEmpty(headVOS)) {
                Map<Long, Integer> longIntegerMap = materielType(headVOS);
                List<ProductionPlanDO> saveVo = new ArrayList<>();
                List<ProductionPlanDO> updateVo = new ArrayList<>();
                headVOS.stream().forEach(aa -> {
                    ProductionPlanDO vo = new ProductionPlanDO();
                    //主键    --->   FInterId
                    Long id = Long.parseLong(aa.getFInterId());
                    vo.setId(id);
//                    vo.setSourceType(Long.parseLong(aa.getFSourceTranType()));
                    vo.setSourceType(ConstantForMES.SALE_ORDER);
                    //工艺路线
                    log.info("------------工艺路线主键"+aa.getCraftId());
                    vo.setTecRouteId(aa.getCraftId());
                    //kis无工艺路线
//                    vo.setTecRouteId(Long.parseLong(aa.getFRoutingID()));
                    //来源单ID 取---->FSourceInterId; 源单内码  固定对应 gyhl 的 销售订单 93L  FOrderInterID  FSourceInterId
                    vo.setSourceId(Long.parseLong(aa.getFOrderInterID()==null?aa.getFSourceInterId():aa.getFOrderInterID()));
//                    vo.setSourceId(ConstantForMES.SALE_ORDER);
                    // 源单编号 取 kis 的  FSourceBillNo
                    vo.setSourceNo(aa.getFSourceBillNo());
                    //计划单号 ------>编码
                    vo.setPlanNo(aa.getFBillNo());
                    //物料id  --->FOtemId
                    Long  materielId = Long.parseLong(aa.getFItemID());
                    vo.setMaterielId(materielId);
                    vo.setProDept(Long.parseLong(aa.getFUnitID()));
                    //TODO 生产了类型 FWorktypeID 默认为 普通订单
//                    1052        手工录入
//                    1053        手工分解
//                    11077        MRP产生
//                    11078        初始化在
//                    aa.getFMRP()
                    vo.setType(ConstantForMES.REGINLAR_ORDER);
                    vo.setIsQuota(0);
                    //计划生产数量
                    vo.setPlanCount(new BigDecimal(aa.getFauxqty()));
//                    vo.setPlanCountSupport(new BigDecimal(aa.getFauxqty()));
                    vo.setBatchNo(aa.getFGMPBatchNo());

                    vo.setPlanStartTime(timeToTranslateForDate(aa.getFPlanCommitDate()));
                    vo.setPlanEndTime(timeToTranslateForDate(aa.getFPlanFinishDate()));

                    vo.setBomId(Long.parseLong(aa.getFBomInterID()));
                    vo.setCompletionMax(new BigDecimal(aa.getFAuxInHighLimitQty()));
                    vo.setCompletionMin(new BigDecimal(aa.getFAuxInLowLimitQty()));
                    vo.setIsCheck(0);
                    //客户主键  无
                    vo.setClientName(aa.getFHeadSelfJ0187());
                    vo.setDeliveryDate(timeToTranslateForDate(aa.getFHeadSelfJ0194()));
                    //下达时间/
                    vo.setGiveTime((timeToTranslateForDate(aa.getFCommitDate())));
                    //结案时间
                    vo.setActualFinishTime((timeToTranslateForDate(aa.getFCloseDate())));
                    // TODO  kis的生产任务状态为 Fstatus==5确认 or Fstatus==1下达  允许同步   默认拉取的是已下达的状态，亲测结果
//                    Long status = Long.parseLong(StringUtils.isNotBlank(aa.getFstatus()) ? aa.getFstatus() : "0");
//                    if(Objects.equals(ConstantForMES.AFFIRM_OF_KIS,status)){
//                        vo.setStatus(ConstantForMES.AFFIRM);
//                    }else{
//                        vo.setStatus(ConstantForMES.ISSUED);
//                    }
                    vo.setStatus(ConstantForMES.ISSUED);
                    // 组装日报   成型日报
                    vo.setNewType( longIntegerMap.containsKey(materielId)?longIntegerMap.get(materielId):1);
//                    vo.setMaterielId();UpkeepRecordServiceImpl
                    //审核人 ----> 确认人
                    vo.setAuditor(Long.parseLong(StringUtils.isNotBlank(aa.getFConfirmerID())?aa.getFConfirmerID():"0"));
                    //制单人 ----> 下达人
                    vo.setCreateBy(Long.parseLong(StringUtils.isNotBlank(aa.getFConveyerID())?aa.getFConveyerID():"0"));
                    //创建时间
                    vo.setCreateTime((timeToTranslateForDate(aa.getFCheckDate())));
                    //更新时间 ----->  单据确认日期 ***
                    vo.setUpdateTime((timeToTranslateForDate(aa.getFConfirmDate())));
                    vo.setDelFlag(0);
                    vo.setIsCollect(0);
                    if (bodyIdsAndHeadIds.containsKey(id)) {
                        updateVo.add(vo);
                    } else {
                        saveVo.add(vo);
                    }
                });
//                List<ProductionPlanDO> voAll = new ArrayList<>();
                if (!CollectionUtils.isEmpty(saveVo)) {
                    log.info("--------------生产计划新增："+saveVo.size());
                    int i = billDao.batchSaveProductionPlan(saveVo);
                    log.info("--------------生产计划新增 完成："+i);
//                    voAll.addAll(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    log.info("--------------生产计划更新："+updateVo.size());
                    int ii = billDao.batchUpdateProductionPlan(updateVo);
                    log.info("--------------生产计划更新： 完成："+ii);
//                    voAll.addAll(updateVo);
                }
                //生成工序计划
//                if (!CollectionUtils.isEmpty(voAll)) {
//                    this.automaticWorkingProcedurePlan(voAll);
//                }
            }
            log.info("-----------结束 --- 生成计划----同步结束！");
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info(" 保存更新 生产计划 异常！");
//        }
    }

    /** -------------------------------------------------------------------------------------------------------------------------- */


    /**   生产投料单 */
    @Override
    public R productionFeedingSync(int itemClassId) {
        //校验 + 限制频繁调用
        Pair<Boolean, String> pair = this.limitFrequentCalls("_allProductionFeeding");
        if (pair.getLeft()) {
            return R.error(pair.getRight());
        }
        //查询出通知所有的主键 和审核时间
        Pair<Map<Long, Long>, Map<String, Long>> allOldIds = idsAndAuditTime(itemClassId);
        Map<String, String> paramForApi = paramForApi(itemClassId, false,"FCheckDate");
        R r = this.doPostOfApiForProductionFeeding(kisApiUrlParam.getUrl_pull_bill(), paramForApi, allOldIds);
        //标记定时任务执行是否
        this.markSynchronized("productionFeeding_synchronized_005");
        return r;
    }

    public R doPostOfApiForProductionFeeding(String url, Map<String, String> params, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        try {
            String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
            if (StringUtils.isNotBlank(result)) {
                Object parse = JSON.parse(result);
                ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
                System.out.println("-----------投料计划--返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
                if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                    // 0 为正常  1 异常
                    return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
                }
                String datas = apiResultVOS.getDatas();
                List<HeadAndBodyVO> kisHeadAndBodyVO = JSON.parseArray(datas, HeadAndBodyVO.class);
                if (!CollectionUtils.isEmpty(kisHeadAndBodyVO)) {
                    //保存 更新
                    keepUpdateForProductionFeeding(kisHeadAndBodyVO, allOldIds);
                }
            }
            return R.ok();
        } catch (Exception e) {
            return R.error("调用api或转换异常：" + e.getMessage());
        }
    }

    public void keepUpdateForProductionFeeding(List<HeadAndBodyVO> kisHeadAndBodyVO, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        List<ProductionFeedingHeadVO> headVOS = new ArrayList<>();
        List<ProductionFeedingBodyVO> bodyVOS = new ArrayList<>();
        for (HeadAndBodyVO vo : kisHeadAndBodyVO) {
            String billHead = vo.getBillHead();
            String billEntry = vo.getBillEntry();
            if (StringUtils.isNotBlank(billHead) && StringUtils.isNotBlank(billHead)) {
                ProductionFeedingHeadVO productionFeedingHeadVO = JSON.parseObject(JSON.parse(billHead).toString(), ProductionFeedingHeadVO.class);
                List<ProductionFeedingBodyVO> productionFeedingBodyVO = JSON.parseArray(billEntry, ProductionFeedingBodyVO.class);
                headVOS.add(productionFeedingHeadVO);
                bodyVOS.addAll(productionFeedingBodyVO);
            }
        }
        //更新 保存
        disposeHeadProductionFeeding(headVOS, allOldIds.getLeft());
        disposeBodyProductionFeeding(bodyVOS, allOldIds.getRight());
    }


    @Async("createPDFExecutor")
    public void disposeHeadProductionFeeding(List<ProductionFeedingHeadVO> headVOS, Map<Long, Long> headIdsAndTime) {
        //字段匹配转换 更新 保存
        try {
            if (!CollectionUtils.isEmpty(headVOS)) {
                Date date = new Date();
                List<ProductionFeedingDO> saveVo = new ArrayList<>();
                List<ProductionFeedingDO> updateVo = new ArrayList<>();
                headVOS.stream().forEach(aa -> {
                    ProductionFeedingDO vo = new ProductionFeedingDO();
                    long id = Long.parseLong(aa.getFInterId());
                    vo.setId(id);
                    vo.setProductionPlanId(Long.parseLong(aa.getFICMOInterID()));
                    vo.setType(Long.parseLong(aa.getFType()));
                    vo.setFeedingNo(aa.getFBillNo());
                    //已审核
                    vo.setStatus(179L);
                    vo.setMaterielId(Long.parseLong(aa.getFItemID()));
                    vo.setProDept(Long.parseLong(aa.getFWorkShop()==null?"0":aa.getFWorkShop()));
                    vo.setPlanCount(new BigDecimal(aa.getFAuxQty()));
                    vo.setIsQuota(0);
                    vo.setAuditor(Long.parseLong(aa.getFCheckerID()));
                    vo.setCreateBy(Long.parseLong(aa.getFBillerID()));
                    //创建时间 取 ----> 审核日期
                    vo.setCreateTime((timeToTranslateForDate(aa.getFCheckDate())));
                    vo.setUpdateBy(Long.parseLong(aa.getFBillerID()));
                    vo.setUpdateTime(date);
//                    vo.setConvCoefficient(new BigDecimal("1"));
                    //辅助单位  取  -----> 单位
//                    vo.setSupportUom(Long.parseLong(aa.getFUnitID()));
                    vo.setDelFlag(0);
                    if (headIdsAndTime.containsKey(id)) {
                        updateVo.add(vo);
                    } else {
                        saveVo.add(vo);
                    }
                });
                if (!CollectionUtils.isEmpty(saveVo)) {
                    billDao.batchSaveProductionFeeding(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    billDao.batchUpdateProductionFeeding(updateVo);
                }

                try {
                    //因为不能同步金蝶的删除曹祖，所以当生产任务单已存在投料单时，删除老的投料单
                    filterFeedingSync();
                }catch (Exception e) {
                    e.printStackTrace();
                    log.error("==========================投料单去重失败");
                    throw e;
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 生产投料单 头  异常！");
        }
    }

    public R filterFeedingSync() {

        HashMap<String, Object> feedMap = new HashMap<>();
        List<Long> planIds = productionFeedingDetailDao.feedingCountGroupByPlanId(feedMap);

        feedMap.put("planIds",planIds);
        feedMap.put("delFlag",0);
        feedMap.put("sort","create_time");
        feedMap.put("sort2","feeding_no");
        List<ProductionFeedingDO> feedings = productionFeedingDao.list(feedMap);
        Map<Long, List<ProductionFeedingDO>> feedingsGroupByPlanId = feedings.stream().collect(Collectors.groupingBy(ProductionFeedingDO::getProductionPlanId));
        for(Map.Entry<Long, List<ProductionFeedingDO>> entry : feedingsGroupByPlanId.entrySet()){
            List<ProductionFeedingDO> value = entry.getValue();
            feedings.remove(value.get(0));
        }
        List<Long> feedIds = feedings.stream().map(ProductionFeedingDO::getId).collect(Collectors.toList());
        productionFeedingDao.batchRemove2(feedIds);
        return R.ok();

    }

    @Async("createPDFExecutor")
    public void disposeBodyProductionFeeding(List<ProductionFeedingBodyVO> bodyVOS, Map<String, Long> bodyIdsAndHeadIds) {
        //字段匹配转换 更新 保存
        try {
            if (!CollectionUtils.isEmpty(bodyVOS)) {
                Date date = new Date();
                List<ProductionFeedingDetailDO> saveVo = new ArrayList<>();
                List<ProductionFeedingDetailDO> updateVo = new ArrayList<>();
                bodyVOS.stream().forEach(aa -> {
                    ProductionFeedingDetailDO vo = new ProductionFeedingDetailDO();
                    //字表主键自动生成
                    long interId = Long.parseLong(aa.getFInterId());
                    vo.setHeadId(interId);
                    vo.setMaterielId(Long.parseLong(aa.getFItemID()));
                    vo.setBatchNo(aa.getFBatchNo());
                    //计划投料数量(主单位) ---> FAuxQtyMust 计划投料数量
                    //主辅单位数量一致
                    BigDecimal count = new BigDecimal(aa.getFAuxQtyMust());
                    vo.setPlanFeeding(count);
//                    vo.setPlanFeedingSupport(count);
                    vo.setOutCount(new BigDecimal(aa.getFAuxStockQty()));
                    vo.setScrapCount(new BigDecimal(aa.getFDisCardAuxQty()));
                    vo.setUpdateTime(date);
                    vo.setDelFlag(0);
                    vo.setFacilityId(Long.parseLong(aa.getFStockID()));
                    vo.setLocationId(Long.parseLong(aa.getFSPID()));
                    vo.setIsCollect(0);
                    String entryIDInterId = interId + "-" + aa.getFEntryID();
                    if (bodyIdsAndHeadIds.containsKey(entryIDInterId)) {
                        vo.setId(bodyIdsAndHeadIds.get(entryIDInterId));
                        updateVo.add(vo);
                    } else {
                        //作为更新或新增的标记
                        vo.setInteridEntryid(entryIDInterId);
                        saveVo.add(vo);
                    }
                });
                if (!CollectionUtils.isEmpty(saveVo)) {
                    billDao.batchSaveProductionFeedingDetail(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    billDao.batchUpdateProductionFeedingDetail(updateVo);
                }
            }
        } catch (Exception e) {
            log.error("保存更新 生产投料单 明细  异常:{}",e);
        }
    }

    /**
     * --------------------------------------------------------------------------------------------------------------------------
     */

    /**   BOM 单 */
    @Override
    public R bomSync(int itemClassId) {
        //校验 + 限制频繁调用
        Pair<Boolean, String> pair = this.limitFrequentCalls("_bom-bill");
        if (pair.getLeft()) {
            return R.error(pair.getRight());
        }
        //查询出通知所有的主键 和审核时间
        Pair<Map<Long, Long>, Map<String, Long>> allOldIds = idsAndAuditTime(itemClassId);
        Map<String, String> paramForApi = paramForApi4(itemClassId, false,"FAudDate");
        paramForApi.remove("Filter");
        log.info("-----------bom参数"+paramForApi);
        R r = this.doPostOfApiForBom(kisApiUrlParam.getUrl_pull_bill(), paramForApi, allOldIds);
        //标记定时任务执行
        markSynchronized("bom_bill_synchronized_003");
        return r;
    }
    public Map<String, String> paramForApi4(int itemClassId, Boolean sign,String param) {
        String week = DatesUtil.getBeginDayOfWeekOfString();
        //TODO 日期放开
//        String yesterday = "2021-12-10";
        Map<String, String> paramForApi = ApiParam.paramApiForBasics(itemClassId, sign);
//        String dd = " and t1."+param+">=" + "'" + week + "'";
//        paramForApi.put("Filter", dd);
        System.out.println("-----------------参数：" + paramForApi);
        return paramForApi;
    }
    public R doPostOfApiForBom(String url, Map<String, String> params, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        try{
            String result = HttpClientUtils.sendJsonStr(url, JSONObject.toJSONString(params));
            if (StringUtils.isNotBlank(result)) {
                Object parse = JSON.parse(result);
                ApiResultVOS apiResultVOS = JSON.parseObject(parse.toString(), ApiResultVOS.class);
//                System.out.println("-------------返回值   整理1  ----ApiResultVOS:" + apiResultVOS);
                if (!JiateConstant.ZERO.equals(apiResultVOS.getStatus())) {
                    // 0 为正常  1 异常
                    return R.error("同步api 返回值状态码异常：" + apiResultVOS.getMsg());
                }
                String datas = apiResultVOS.getDatas();
                List<HeadAndBodyVO> kisHeadAndBodyVO = JSON.parseArray(datas, HeadAndBodyVO.class);
                if (!CollectionUtils.isEmpty(kisHeadAndBodyVO)) {
                    //保存 更新
                    keepUpdateForBom(kisHeadAndBodyVO, allOldIds);
                }
            }
            return R.ok();
        } catch (Exception e) {
            return R.error("调用api或转换异常：" + e.getMessage());
        }
    }

    public void keepUpdateForBom(List<HeadAndBodyVO> kisHeadAndBodyVO, Pair<Map<Long, Long>, Map<String, Long>> allOldIds) {
        List<BomHeadVO> headVOS = new ArrayList<>();
        List<BomBodyVO> bodyVOS = new ArrayList<>();
        for (HeadAndBodyVO vo : kisHeadAndBodyVO) {
            String billHead = vo.getBillHead();
            String billEntry = vo.getBillEntry();
            if (StringUtils.isNotBlank(billHead) && StringUtils.isNotBlank(billHead)) {
                BomHeadVO bomHeadVO = JSON.parseObject(JSON.parse(billHead).toString(), BomHeadVO.class);
                List<BomBodyVO> bomBodyVO = JSON.parseArray(billEntry, BomBodyVO.class);
                headVOS.add(bomHeadVO);
                bodyVOS.addAll(bomBodyVO);
            }
        }
        //更新 保存
        disposeHeadBom(headVOS, allOldIds.getLeft());
        disposeBodyBom(bodyVOS, allOldIds.getRight());
    }

    @Async("createPDFExecutor")
    public void disposeHeadBom(List<BomHeadVO> headVOS, Map<Long, Long> headIdsAndTime) {
        //字段匹配转换 更新 保存
        try {
            if (!CollectionUtils.isEmpty(headVOS)) {
                List<BomDO> saveVo = new ArrayList<>();
                List<BomDO> updateVo = new ArrayList<>();
//                headVOS.stream().forEach(aa -> {
                try{
                    for(BomHeadVO aa:headVOS){
                        BomDO bomDO = new BomDO();
                        long id = Long.parseLong(aa.getFInterId());
                        bomDO.setId(id);
                        bomDO.setSerialno(aa.getFBOMNumber());
                        bomDO.setName("金蝶BOM"+aa.getFBOMNumber());
                        bomDO.setType(Long.parseLong(aa.getFBomType()));
                        bomDO.setVersion(aa.getFVersion());
                        bomDO.setMaterielId(Long.parseLong(aa.getFItemID()));
                        BigDecimal count = new BigDecimal(aa.getFAuxQty());
                        count.setScale(2,BigDecimal.ROUND_DOWN);
                        bomDO.setCount(count);
                        bomDO.setAuditor(Long.parseLong(aa.getFCheckerID()));
                        bomDO.setRemarks(aa.getFNote());
                        bomDO.setAuditSign(179L);
//                        bomDO.setUseStatus(Integer.parseInt(aa.getFUseStatus()));
                        int status = Integer.parseInt(aa.getFUseStatus());

                        // 启用：1 - 1072；禁用：0 - 1073
                        if(status==1072){
                            bomDO.setUseStatus(1);
                        }else if (status == 1073){
                            bomDO.setUseStatus(0);
                        }
                        bomDO.setCreateBy(Long.parseLong(aa.getFCheckID()));
                        bomDO.setCreateTime(timeToTranslateForDate(aa.getFCheckDate()));
                        //更新新时间放审核时间
                        Date date = timeToTranslateForDate(aa.getFAudDate());
//                        log.info("-----审核时间1-----："+date);
                        bomDO.setUpdateTime(timeToTranslateForDate(aa.getFAudDate()));
                        bomDO.setDelFlag(0);
//                        log.info("-----审核时间-放置结束----：");
                        if (headIdsAndTime.containsKey(id)) {
                            updateVo.add(bomDO);
                        } else {
                            saveVo.add(bomDO);
                        }
//                });
                    }
                }catch (Exception e){
                    log.info("处理 bom  头部信息！异常:"+e.getMessage());

                }
                if (!CollectionUtils.isEmpty(saveVo)) {
                    log.info("-----新增 bom ----："+saveVo);
                    billDao.batchSaveBom(saveVo);
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    log.info("-----更新 bom ----："+updateVo);
                    billDao.batchUpdateBom(updateVo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info(" 保存更新 bom  头  异常！:"+e.getMessage());
        }
    }

    @Async("createPDFExecutor")
    public void disposeBodyBom(List<BomBodyVO> bodyVOS, Map<String, Long> bodyIdsAndHeadIds) {
        //字段匹配转换 更新 保存
        System.out.println("----------------body 原值：bodyIdsAndHeadIds：" + bodyIdsAndHeadIds);
//        try {
            if (!CollectionUtils.isEmpty(bodyVOS)) {
                List<BomDetailDO> saveVo = new ArrayList<>();
                List<BomDetailDO> updateVo = new ArrayList<>();
                bodyVOS.stream().forEach(aa -> {
                    BomDetailDO bomDetailDO = new BomDetailDO();
                    bomDetailDO.setBomId(Long.parseLong(aa.getFInterId()));
                    bomDetailDO.setMaterielId(Long.parseLong(aa.getFItemID()));
                    //有基本单位用量   FQty   和  用量  FAuxQty
                    bomDetailDO.setStandardCount(new BigDecimal(aa.getFQty()));
                    bomDetailDO.setWasteRate(new BigDecimal(aa.getFScrap()));
                    bomDetailDO.setProcessId(Long.parseLong(aa.getFOperID()));
                    bomDetailDO.setMaterielType( Integer.parseInt(aa.getFMaterielType()));
                    //工序
                    bomDetailDO.setStationName(aa.getFMachinePos());
//                    bomDetailDO.setStationId();
                    bomDetailDO.setRemarks(aa.getFNote());
                    bomDetailDO.setDelFlag(0);
                    //主单位用量
//                    bomDetailDO.setUnitUomCount(new BigDecimal(aa.getFAuxQty()));

                    String noticeIdEntryId = aa.getFInterId() + "-" + aa.getFEntryID();
                    if (bodyIdsAndHeadIds.containsKey(noticeIdEntryId)) {
                        bomDetailDO.setId(bodyIdsAndHeadIds.get(noticeIdEntryId));
                        updateVo.add(bomDetailDO);
                    } else {
                        //作为更新或新增的标记
                        bomDetailDO.setInteridEntryid(noticeIdEntryId);
                        saveVo.add(bomDetailDO);
                    }
                });
                if (!CollectionUtils.isEmpty(saveVo)) {
                    billDao.batchSaveBomDetail(saveVo);
                    log.info(" 保存更新 bom 明细 保存  完成！");
                }
                if (!CollectionUtils.isEmpty(updateVo)) {
                    billDao.batchUpdateBomDetail(updateVo);
                    log.info(" 保存更新 bom 明细 更新 完成！");
                }
                log.info(" 保存更新 bom 明细 更新 完成！");
            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info(" 保存更新 bom 明细  异常！"+e.getMessage());
//        }
    }


}
